﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace FastEmit
{
    public class MethodAccessor
    {
        private readonly Type _type;

        private readonly Dictionary<string, MethodInvoker> dict = [];

        public MethodAccessor(Type type)
        {
            _type = type;
            var flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance;
            var methods = type.GetMethods(flags);
            foreach (var item in methods)
            {
                //跳过 get_ 和set_等特殊方法
                if (item.IsSpecialName)
                {
                    continue;
                }

                try
                {
                    dict.Add(item.Name, MethodInfoExtensions.DelegateForCallMethod(item));
                }
                catch { }
            }
        }

        public object CallMethod(object obj, string name, params object[] parameters)
        {
            return dict[name](obj, parameters);
        }

#if NET45 || NETSTANDARD2_0 || NET6_0
        public Task<object> CallMethodAsync(object obj, string name, params object[] parameters)
        {
            return FastEmitFactory.GetTaskResultAsync(dict[name](obj, parameters));
        }

        public async Task CallVoidMethodAsync(object obj, string name, params object[] parameters)
        {
            var task = dict[name](obj, parameters) as Task;
            await task;
        }
#endif
        public object CallStaticMethod(string name, params object[] parameters)
        {
            return dict[name](_type, parameters);
        }

#if NET45 || NETSTANDARD2_0 || NET6_0
        public Task<object> CallStaticMethodAsync(string name, params object[] parameters)
        {
            return FastEmitFactory.GetTaskResultAsync(dict[name](_type, parameters));
        }

        public async Task CallStaticVoidMethodAsync(string name, params object[] parameters)
        {
            var task = dict[name](_type, parameters) as Task;
            await task;
        }

#endif
        public MethodInvoker GetInvoker(string name)
        {
            return dict[name];
        }

        public IEnumerable<string> NameList => dict.Select(s => s.Key);
    }

}
